/**
 * AI工具类 - 用于微信小程序调用SidaAI API
 */
import config from './config.js';
// eslint-disable-next-line id-match
import { MODEL_INFERENCE_MAP } from './constants.js';
import { setWatermarkJson, setPath } from './watermarkTool.js';
import md5 from 'js-md5';
class SidaAI {
	constructor() {
		this.baseUrl = config.modelServer;
	}

	/**
   * 加载模型
   * @param {string} businessType - 业务类型：signin/signout/common_model/cleaning_model
   * @param {string} mode - 模式：determine/detect/brightness/pit_area
   * @returns {Promise} 返回加载结果
   */
	loadModel(businessType, mode) {
		if (!mode) {
			return Promise.reject(new Error('请选择一个模式'));
		}
		return new Promise((resolve, reject) => {
			wx.request({
				url: `${this.baseUrl}/SidaAIInit/${businessType}/${mode}`,
				timeout: 6000,
				method: 'GET',
				success: (res) => {
					resolve(res.data);
				},
				fail: (error) => {
					reject(error);
				}
			});
		});
	}

	/**
   * 加载模型（多模型） 
   * @param {string} models - 模型列表：[["signin", "determine"],["cleaning_model", "lift_roof_area"]]
   * @returns {Promise} 返回加载结果
   */
	loadModels(models = []) {
		if (models.length == 0) {
			return Promise.reject(new Error('模型不能为空'));
		}
		return new Promise((resolve, reject) => {
			wx.request({
				url: `${this.baseUrl}/SidaAIInit`,
				method: 'post',
				data: {
					business_type_mode: models
				},
				success: (res) => {
					resolve(res.data);
				},
				fail: (error) => {
					reject(error);
				}
			});
		});
	}

	/**
   * 卸载模型
   * @param {string} businessType - 业务类型
   * @param {string} mode - 模式
   * @returns {Promise} 返回卸载结果
   */
	unloadModel(businessType, mode) {
		if (!mode) {
			return Promise.reject(new Error('请选择一个模式'));
		}
		return new Promise((resolve, reject) => {
			wx.request({
				url: `${this.baseUrl}/SidaAIRelease/${businessType}/${mode}`,
				method: 'GET',
				timeout: 3000,
				success: (res) => {
					resolve(res.data);
				},
				fail: (error) => {
					reject(error);
				}
			});
		});
	}

	/**
	 * 图片推理（ai+清晰度模型+翻拍）
	 * @param {string} businessType - 业务类型 0则不走主模型 走 清晰度模型+翻拍
	 * @param {string} imagePath - 图片路径（本地临时文件路径）
	 * @returns {Promise} 返回推理结果
	 */
	async inferImageWithClarity(businessType = 0, imagePath) {
		const result = await this.inferImage(businessType, imagePath);
		const clarity = await this.inferImage(MODEL_INFERENCE_MAP.CLARITY, imagePath);
		this.inferImageMultiModel(businessType , imagePath);
		return {
			results: {
				...result.results || {},
				...clarity.results || {}
			}
		};
	}

	/**
   * 多模型图片推理（没加载则补充加载
   * @param {string} businessType - 业务类型
   * @param {string} mode - 模式{}
   * @param {string} imagePath - 图片路径（本地临时文件路径）
   * @returns {Promise} 返回推理结果
   */
	async inferImageMultiModel(businessType = 0, imagePath) {
		console.log('inferImageMultiModel',businessType);
		let mode = 'determine';
		switch (businessType) {
		case MODEL_INFERENCE_MAP.PIT_AREA_CLEANING:
			mode = 'pit_area';
			break;
		case MODEL_INFERENCE_MAP.LIFT_ROOF_AREA_CLEANING:
			mode = 'lift_roof_area';
			break;
		case MODEL_INFERENCE_MAP.LAYER_SILL_AREA_CLEANING:
			mode = 'layerSill_area';
			break;
		case MODEL_INFERENCE_MAP.CLARITY:
			mode = 'clarity';
			break;
		case MODEL_INFERENCE_MAP.TENS:
			mode = 'tens';
			break;
		default:
			mode = 'determine';
		}

		// if (!mode) {
		// 	return Promise.reject(new Error('请选择一个模式'));
		// }
		if (!imagePath) {
			return Promise.reject(new Error('请提供图片路径'));
		}
		const type = this.getAvailableModes(businessType); 
		let models = [['common_model','clarity'],['common_model','moore_pattern']];
		if (businessType != 0 && type) {
			models.push([type,mode]);
		} 
		try {
			let result = await this.getModelsResult(models, imagePath);
			if (result && result.detail && result.detail.indexOf('SidaAIInit') != -1) {
				// 模型未加载 加载完后再重新跑识别
				await this.loadModels(models);
				await this.awaitTimes(100);
				result = await this.getModelsResult(models, imagePath);
			}
			let determine = -1;
			let results = {};
			if (result && result.results) {
				determine = this.getDetermine(result.results); 
				for (let i = 0; i < result.results.length; i++) {
					const item = result.results[i];
					if (item && typeof item === 'object') {
						Object.keys(item).forEach(key => {
							results[key] = item[key];
						});
					}
				}
				results.determine = determine;
				 
				return   {results:results,determine};
			} else {
				return   {};
			}
		} catch (error) {
			console.log('ai-89', error);
			return {};
		}
	}

	/**
   * 图片推理（没加载则补充加载
   * @param {string} businessType - 业务类型
   * @param {string} mode - 模式{}
   * @param {string} imagePath - 图片路径（本地临时文件路径）
   * @returns {Promise} 返回推理结果
   */
	async inferImage(businessType, imagePath) {
		let mode = 'determine';
		switch (businessType) {
		case MODEL_INFERENCE_MAP.PIT_AREA_CLEANING:
			mode = 'pit_area';
			break;
		case MODEL_INFERENCE_MAP.LIFT_ROOF_AREA_CLEANING:
			mode = 'lift_roof_area';
			break;
		case MODEL_INFERENCE_MAP.LAYER_SILL_AREA_CLEANING:
			mode = 'layerSill_area';
			break;
		case MODEL_INFERENCE_MAP.CLARITY:
			mode = 'clarity';
			break;
		case MODEL_INFERENCE_MAP.TENS:
			mode = 'tens';
			break;
		default:
			mode = 'determine';
		}

		if (!mode) {
			return Promise.reject(new Error('请选择一个模式'));
		}
		if (!imagePath) {
			return Promise.reject(new Error('请提供图片路径'));
		}
		const type = this.getAvailableModes(businessType);
		
		if (!type) {
			return {};
		}
		try {
			let result = await this.getModelResult(type, mode, imagePath);
			if (result && result.detail && result.detail.indexOf('SidaAIInit') != -1) {
				await this.loadModel(type, mode);
				await this.awaitTimes(100);
				result = await this.getModelResult(type, mode, imagePath);
			}
			let determine = -1;
			if (result && result.results) {
				determine = this.getDetermine(result.results);
				result.determine = determine;
			}
		
			return result || {};
		} catch (error) {
			console.log('ai-89', error);
			return {};
		}
	}

	/**
	 * 视频推理（应急灯模型专用）
	 * @param {string} videoPath - 视频文件路径（本地临时文件路径）
	 * @returns {Promise} 返回推理结果
	 */
	async inferVideo(videoPath) {
		const businessType = 'device_model';
		const mode = 'emergencyLight';
		console.log('inferVideo', businessType, mode, videoPath);
		if (!videoPath) {
			return Promise.reject(new Error('请提供视频文件路径'));
		}

		try {
			await this.loadModel(businessType, mode);
			await this.awaitTimes(300);
			const result = await this.getVideoModelResult(businessType, mode, videoPath);
			return result || {};
		} catch (error) {
			console.log('video-infer-error', error);
			return {};
		} finally {
			await this.unloadModel(businessType, mode);
		}
	}

	// 获取模型识别结果determine
	getDetermine(jsonObj) {
		// -1 无法识别 0 正常 1 疑似 2不合规
		const jsonString = JSON.stringify(jsonObj);
		const determinePattern = /"determine"\s*:\s*(-?\d+\.?\d*)/g;
		const matches = [];
		let match;

		while ((match = determinePattern.exec(jsonString)) !== null) {
			matches.push(Number(match[1]));
		}

		let determine = -1;
		for (let i = 0; i < matches.length; i++) {
			if (matches[i] > determine) {
				determine = matches[i];
			}
		}

		return determine;
	}

	awaitTimes(timeout) {
		return new Promise((resolve) => {
			setTimeout(() => {
				resolve();
			}, timeout);
		});
	}

	/**
   * 获取图片推理结果
   * @param {string} businessType - 业务类型
   * @param {string} mode - 模式
   * @param {string} imagePath - 图片路径（本地临时文件路径）
   * @returns {Promise} 返回推理结果
   */
	getModelResult(businessType, mode, imagePath) {
		return new Promise((resolve, reject) => {
			wx.uploadFile({
				url: `${this.baseUrl}/SidaAIInfer/${businessType}/${mode}`,
				filePath: imagePath,
				name: 'image',
				success: (res) => {
					try {
						const data = JSON.parse(res.data);
						resolve(data);
					} catch (error) {
						reject(new Error('解析响应数据失败'));
					}
				},
				fail: (error) => {
					reject(error);
				}
			});
		});
	}

	// 
	// 获取图片推理结果 (多模型组合) 
	// @param {string} models - 模型组,例: [["signin","determine"],["cleaning_model","lift_roof_area"]]
	// @param {string} imagePath - 图片路径（本地临时文件路径）
	// @returns {Promise} 返回推理结果
	// 
	getModelsResult(models, imagePath) {
		return new Promise((resolve, reject) => {
			wx.uploadFile({
				url: `${this.baseUrl}/SidaAIInfer`,
				filePath: imagePath,
				name: 'image',
				formData: {
					sidaaiinfer_input: JSON.stringify(
						{ 'business_type_mode':models })
				},
				success: (res) => {
					try {
						const data = JSON.parse(res.data);
						resolve(data);
					} catch (error) {
						reject(new Error('解析响应数据失败'));
					}
				},
				fail: (error) => {
					reject(error);
				}
			});
		});
	}

	/**
	 * 获取视频推理结果
	 * @param {string} businessType - 业务类型
	 * @param {string} mode - 模式
	 * @param {string} videoPath - 视频文件路径（本地临时文件路径）
	 * @returns {Promise} 返回推理结果
	 */
	getVideoModelResult(businessType, mode, videoPath) {
		return new Promise((resolve, reject) => {
			wx.uploadFile({
				url: `${this.baseUrl}/SidaAIInferVideo/${businessType}/${mode}`,
				filePath: videoPath,
				timeout: 30000,
				name: 'video',
				success: (res) => {
					try {
						const data = JSON.parse(res.data);
						resolve(data);
					} catch (error) {
						reject(new Error('解析响应数据失败'));
					}
				},
				fail: (error) => {
					reject(error);
				}
			});
		});
	}

	getAvailableModes(businessType) {
		const modeMap = { 
			1: 'signin',
			2: 'signout',
			3: 'cleaning_model',
			4: 'cleaning_model',
			5: 'cleaning_model',
			6: 'common_model',
			7: 'device_model',
			8: 'device_model'
		};
		return modeMap[businessType] || '';
	}

	/**
	 * 处理视频选择后的AI结果（微信小程序版本）
	 * @param {Object} params - 参数对象
	 * @param {number} params.modelType - 模型类型
	 * @param {string} params.tempFilePath - 视频临时文件路径
	 * @param {Object} params.modelIdMap - 模型ID映射表
	 * @param {Object} params.offlineConfig - 离线配置
	 * @param {Object} params.checkHistory - 检查历史记录
	 * @param {string} params.planId - 计划ID
	 * @returns {Promise<Object>} 返回处理结果 {imgId, aiResult, modelId}
	 */
	async processVideoAIResult(params) {
		const {
			modelType,
			tempFilePath,
			modelIdMap,
			offlineConfig,
			checkHistory,
			planId
		} = params;

		let imgId = '';
		let aiResult = '';
		let modelId = '';

		// 只有在模型类型有效且有视频文件路径时才进行AI推理
		if (modelType !== -1 && tempFilePath) {
			try {
				console.log('[SidaAI] 开始调用inferVideo，视频路径:', tempFilePath);
				const videoInferResult = await this.inferVideo(tempFilePath);
				console.log('[SidaAI] inferVideo返回结果:', JSON.stringify(videoInferResult));

				// 如果有 AI 处理结果，处理并保存数据
				if (videoInferResult && videoInferResult.status === 200 && videoInferResult.results) {
					const processedResult = this._processVideoInferenceResult(
						videoInferResult,
						modelType,
						modelIdMap,
						offlineConfig,
						checkHistory,
						planId
					);

					if (processedResult.obj) {
						imgId = await setWatermarkJson(processedResult.obj);
						// 设置路径关联关系
						const md5Path = md5(tempFilePath);
						setPath(md5Path, imgId);
					}

					aiResult = processedResult.aiResult;
					modelId = processedResult.modelId;
				}
			} catch (error) {
				console.error('[SidaAI] inferVideo调用失败:', error);
			}
		}

		return { imgId, aiResult, modelId };
	}

	/**
	 * 处理视频选择后的AI结果（H5版本）
	 * @param {Object} params - 参数对象
	 * @param {Array|string} params.rawNativeCameraData - 原生相机返回的数据
	 * @param {number} params.modelType - 模型类型
	 * @param {Object} params.modelIdMap - 模型ID映射表
	 * @param {Object} params.offlineConfig - 离线配置
	 * @param {Object} params.checkHistory - 检查历史记录
	 * @param {string} params.planId - 计划ID
	 * @param {string} params.tempFilePath - 视频临时文件路径
	 * @returns {Promise<Object>} 返回处理结果 {imgId, aiResult, modelId}
	 */
	async processH5VideoAIResult(params) {
		const {
			rawNativeCameraData,
			modelType,
			modelIdMap,
			offlineConfig,
			checkHistory,
			planId,
			tempFilePath
		} = params;

		let imgId = '';
		let aiResult = '';
		let modelId = '';

		if (!rawNativeCameraData) {
			return { imgId, aiResult, modelId };
		}

		try {
			console.log('[SidaAI] rawNativeCameraData', rawNativeCameraData);

			// 解析原生相机数据
			const nativeCameraArray = this._parseNativeCameraData(rawNativeCameraData);
			console.log('[SidaAI] nativeCameraArray', nativeCameraArray);

			// 如果数组长度大于2，解析第三个元素（options）
			if (nativeCameraArray.length > 2) {
				const options = this._parseOptionsFromNativeCamera(nativeCameraArray[2]);
				console.log('[SidaAI] 解析到的 options', options);

				// 如果有 AI 处理结果，处理并保存数据
				if (Object.keys(modelIdMap).includes(`${modelType}`) && options.result !== undefined) {
					const processedResult = this._processH5VideoOptions(
						options,
						modelType,
						modelIdMap,
						offlineConfig,
						checkHistory,
						planId
					);

					if (processedResult.obj) {
						imgId = await setWatermarkJson(processedResult.obj);
						// 设置路径关联关系
						const md5Path = md5(tempFilePath);
						setPath(md5Path, imgId);
					}

					aiResult = processedResult.aiResult;
					modelId = processedResult.modelId;
				}
			}
		} catch (error) {
			console.error('[SidaAI] 解析 rawNativeCameraData 失败:', error);
		}

		return { imgId, aiResult, modelId };
	}

	/**
	 * 处理视频推理结果（内部方法）
	 * @private
	 */
	_processVideoInferenceResult(videoInferResult, modelType, modelIdMap, offlineConfig, checkHistory, planId) {
		// 获取业务类型对应的结果 
		const modeType = videoInferResult.mode;
		const businessResults = videoInferResult.results[modeType];

		// 从 offline_config 获取 ai_business_config
		const offlineAiBusinessConfig = offlineConfig?.ai_business_config || {};

		if (businessResults && Object.keys(modelIdMap).includes(`${modelType}`)) {
			// 3-保养工作项内容
			const obj = {
				planId: planId,
				type: 3,
				result: `${businessResults.determine}`,
				model_id: modelIdMap[`${modelType}`],
				watermark: '',
				model_result: JSON.stringify(videoInferResult.results),
				locationIds: checkHistory.locationIds,
				locationNames: checkHistory.locationNames,
				templateContentId: checkHistory.templateContentId,
				templateContentName: checkHistory.templateContentName,
				templateId: checkHistory.templateId,
				templateName: checkHistory.templateName,
				ai_business_config: JSON.stringify(offlineAiBusinessConfig),
				business_result: JSON.stringify(videoInferResult.results),
			};

			return {
				obj,
				aiResult: businessResults.determine,
				modelId: modelIdMap[`${modelType}`]
			};
		}

		return { obj: null, aiResult: '', modelId: '' };
	}

	/**
	 * 解析原生相机数据（内部方法）
	 * @private
	 */
	_parseNativeCameraData(rawNativeCameraData) {
		if (typeof rawNativeCameraData === 'string') {
			// 处理字符串格式的数组 "['path','id','options']"
			return JSON.parse(rawNativeCameraData.replace(/'/g, '"'));
		} else if (Array.isArray(rawNativeCameraData)) {
			return rawNativeCameraData;
		} else {
			console.error('[SidaAI] rawNativeCameraData 格式不正确');
			return [];
		}
	}

	/**
	 * 解析原生相机选项数据（内部方法）
	 * @private
	 */
	_parseOptionsFromNativeCamera(optionsStr) {
		try {
			return JSON.parse(optionsStr);
		} catch (optionsError) {
			console.error('[SidaAI] 解析 options 失败:', optionsError);
			return {};
		}
	}

	/**
	 * 处理H5视频选项（内部方法）
	 * @private
	 */
	_processH5VideoOptions(options, modelType, modelIdMap, offlineConfig, checkHistory, planId) {
		// 从 offline_config 获取 ai_business_config 并与 options 中的配置合并
		const offlineAiBusinessConfig = offlineConfig?.ai_business_config || {};
		const mergedAiBusinessConfig = {
			...offlineAiBusinessConfig,
			...(options.ai_business_config || {})
		};

		// 3-保养工作项内容
		const obj = {
			planId: planId,
			type: 3,
			result: `${options.result}`,
			model_id: modelIdMap[`${modelType}`],
			watermark: options.watermark || '',
			model_result: JSON.stringify(options.model_result || {}),
			locationIds: checkHistory.locationIds,
			locationNames: checkHistory.locationNames,
			templateContentId: checkHistory.templateContentId,
			templateContentName: checkHistory.templateContentName,
			templateId: checkHistory.templateId,
			templateName: checkHistory.templateName,
			ai_business_config: JSON.stringify(mergedAiBusinessConfig),
			business_result: JSON.stringify(options.business_result) || '',
		};

		return {
			obj,
			aiResult: options.result,
			modelId: modelIdMap[`${modelType}`]
		};
	}
}

export default new SidaAI();
